Django + SQLAlchemy: シンプルWay
PyCon JP 2020
https://gyazo.com/abb58be00ce85bbd0974e71811810595
トーク内容
公式URL https://pycon.jp/2020/timetable/?id=203756
slideshare https://www2.slideshare.net/shimizukawa/simple-way-with-django-sqlalchemy-20200828-updated-version
video: https://youtu.be/DyAnzE7r-3M
質疑応答
Ryuji Tsutsui から全員に: 02:58 PM
INNNER JOIN
Nが1個多い?
ほんとだ。slideshareにあげた資料、直せません!
Taku Shimizu から全員に: 03:00 PM
「ドキュメントに記載されていない」なかなかのパワーフレーズですね
でしょー
uranusjr から全員に: 03:04 PM
g2の別名はT3になるのはなぜですか?
Djangoが自動的にテーブルを2回JOINすることもあって、そういう場合自動的にテーブル名の別名が付けられます。T2,T3,T4と連番で増えていきます。たぶん、登場する3つ目のテーブルだからT3なのだと思います。
annotate(g2=FilteredRelation(...) のように名前指定しているのに使われないのは、バグなのかどうなのか追ってません。SQLは動作するので、バグとはいえないかも。
Manabu から全員に: 03:17 PM
SQLAlchemy の モデルクラスを直接書いていましたが、 automap_base() は使わないのですか?
全テーブルを使いたいわけではないのと、用途の目的から、SQLAlchemyでForeignKeyを独自に追加定義したいなどもあるため、個別に書いています。automap_base()を使っても良いと思います。
c-bata から全員に: 03:19 PM
DBのマイグレーションはalembicを使う感じでしょうか?
Dango ORM側で全てマイグレーションするか、それ以外(alembicや生DDL)でマイグレーションするかは統一すればよいと思います。Django ORM側でやるのが楽だと思いますが、Redshiftなどの場合生DDLでやるしかなかったりするし、そういう環境でこそこの方法が有用だったりします。
あ、基本的にDjango ORMを使っていて、難しいクエリだけSQLALchemyでSQL生成している感じですかね。
はい。そういう感じです。
トーク下書き
トークプロポーザル
https://www.papercall.io/speakers/shimizukawa/speaker_talks/183718-django-sqlalchemy-way
質問
みなさん、Djangoに限らず、ORMでクエリ書いてますか?
SQLで書いた方が楽って言う人いますか?
そういう人はDjangoなどのORMがある環境でどうやってSQLを実行してますか?
Django ORMで表現が難しいSQLの例
DjangoのORMはとても便利です。しかし、SQLならすぐに書ける「サブクエリをINNER JOINする」「1つのテーブルを2回OUTER JOINする」といったクエリをDjango ORMで表現するのは苦手です。
DjangoのORMはとても便利ですが、少し複雑なクエリを組み立てようとすると急に難しくなってしまうことがあります。例えば、サブクエリの結果をINNER JOINしたい場合や、1つのテーブルを2回OUTER JOINしたい場合などは、SQLならすぐに書けるのにDjango ORMで表現するのがとても難しかったり、不可能だったりします。
Django ORMで複雑なSQLを書くのが難しい
ForeignKeyがないモデルのJOINができない
ORM上はシンプルなクエリなのに、実行されるSQLが複雑になってしまう
SQLを直接書いてrawやexecuteで実行する例と問題点
このような場合にSQLを直接書いて Model.objects.raw() や execute() で実行する方法もありますが、この方法では動的にSQLを組み替えるのが難しくなったりSQL Injectionのリスクもあります。
SQLAlchemyの紹介と簡単な実行例
SQLAlchemyを使えば、この問題を解決できます。
SQLAlchemyをSQL表現言語として使う事でSQLの組み立てをプログラムで行い、Django上で安全に実行する方法を紹介します。
複雑なSQLをSQLAlchemyで組み立てる
DjangoでSQLAlchemyを使う
SQLAlchemyとDjangoの連携
Django + SQLAlchemy + dataclass
aldjemyを使ってテーブルの再定義を避けられる?
解決できること
サブクエリやOUTER JOINを多用したSQLをシンプルに扱える
参考
Djangoで売上を集計/集約処理する - Make組ブログ
ちなみにDjangoでaggregationの機能が追加されたのは1.1からですね。 (1.1 リリースノート)。
意外とあっさりできましたが、理解するのはちょっとややこしいかも。 annotateの前にvaluesをおいてグループ化してやってるわけですが、SQL脳でみると.group_byなどのメソッドが欲しいなというところ。
これについては何度も議題にあがってるようです。 https://groups.google.com/d/topic/django-developers/dUlwp9z9gGI/discussion
よりORMらしい方法(values-annotateのことかな)が採択されたとのこと。詳細は チケット3566 のようで、このチケットは「ORMで集計できるようにしよう」という提案のようですね。
SQLAlchemyのSQL表現言語で集計する - Make組ブログ
今回はDjango(のORM)ではなく SQLAlchemy を使います。バージョンは0.8。 ただしORMとしてではなく、SQLAlchemyのSQL表現言語(SQLExpression)のみ使います。 (私はSQLAlchemyのド素人で、ORMとして使ったことがないです。ただ、SQLAlchemyの SQL表現言語が素晴らしいなーと思ったので、試してみました)
SQLAlchemyとJupyterNotebookで遊んでみた話 — kashew_nuts-blog
SQLAlchemyべんり。DB操作フレームワークという表現に納得した
プレゼンテーション:Sharding with SQLAlchemy | PyCon JP 2017 in TOKYO
本トークでは、Pythonの代表的なORMであるSQLAlchemyを使って、単一のアプリケーションインスタンスから、Sharding されたデータベースへのアクセスを実現するテクニックを説明します。
SQLALchemyと僕 - PyCon JP 2012
まさしくSQL Toolkit
素の SQL 文の実行 | Django ドキュメント | Django
直接 SQL を書く場合はいかなる時も十分警戒するべきです。それを利用する時は毎回、利用者が 引数 を利用する事で任意に設定可能な全てのパラメータは SQL インジェクション攻撃から防御するため適切にエスケープすべきです。詳細は SQL インジェクションの防御 を参照してください。
62:SQLから逆算してDjango ORMを組み立てる — 自走プログラマー【抜粋版】
理想のSQL を書いてから、そのSQLをORMで発行するように実装しましょう。
FilteredRelation